package com.springboot.demo.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.gson.JsonObject;
import com.springboot.demo.entity.*;
import com.springboot.demo.entity.data.MsgData;
import com.springboot.demo.exception.BusinessException;
import com.springboot.demo.mapper.*;
import com.springboot.demo.service.InboxService;
import com.springboot.demo.service.SceneService;
import com.springboot.demo.service.UserService;
import com.springboot.demo.utils.*
        ;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.validation.constraints.NotNull;
import java.util.*;

/**
 * @author wubc683
 * @desc
 * @date 2021-09-13 9:18
 */
@Service
@Slf4j
public class SceneServiceImpl implements SceneService {
    @Autowired
    SceneMapper sceneMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    InboxService inboxService;
    @Autowired
    InboxMapper inboxMapper;
    @Autowired
    PageUtils pageUtils;
    @Autowired
    DeviceMapper deviceMapper;
    @Autowired
    PanelMapper panelMapper;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    UserService userService;

    @Autowired
    SimpMessagingTemplate simpMessagingTemplate;

    // 组态排序字段
    private static String[] SCENESORTFIELD = {"id", "name", "createDate", "address"};

    @Override
//    @Cacheable(value = "scene", key = "#sid")
    public Scene getSceneInfo(Long uid, Long sid) {
        // 检查组态是否存在
        Scene sceneById = sceneMapper.getSceneById(sid);
        if (sceneById == null) {
            throw new BusinessException(ResponseResult.SCENE_NOT_EXISTED);
        }
        // 检查用户是否拥有此组态
        if (!sceneById.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        return sceneById;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveSceneInfo(Long uid, Scene scene) {
        // 校验组态群组id
        if (scene.getSceneGroupId().compareTo(Constant.UNGROUPED) > 0) {
            SceneGroup sceneGroupByGid = sceneMapper.getSceneGroupByGid(scene.getSceneGroupId());
            if (sceneGroupByGid == null || !sceneGroupByGid.getOwnerId().equals(uid)) {
                throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE_FOLDER);
            }
        }
        // 检查组态名是否重复
        Scene sceneByUidAndSceneName = sceneMapper.getSceneByUidAndSceneName(uid, scene.getName());
        if (sceneByUidAndSceneName != null) {
            throw new BusinessException(ResponseResult.SCENE_NAME_DUPLICATE);
        }
        scene.setCreateDate(new Date());
        scene.setOwnerId(uid);
        scene.setState(Constant.SceneStatus.UNPUBLIC);
        scene.setSize(0L);
        sceneMapper.saveSceneInfo(scene);
        // 创建默认组态仪表盘
        Panel scenePanel = new Panel();
        scenePanel.setName(Constant.ScenePanel.MONITOR_PANEL);
        scenePanel.setCreateDate(new Date());
        scenePanel.setType(Constant.PanelType.SCENE_PANEL);
        scenePanel.setIsDefault(true);
        sceneMapper.saveScenePanelInfo(scenePanel);
        sceneMapper.saveScenePanelBySceneIdAndPanelId(scene.getId(), scenePanel.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void shareSceneInfo(Long ownerId, Long sid, String username) {
        // 检查组态是否存在
        Scene sceneById = sceneMapper.getSceneById(sid);
        if (sceneById == null) {
            throw new BusinessException(ResponseResult.SCENE_NOT_EXISTED);
        }
        // 检查用户是否拥有此组态
        if (!sceneById.getOwnerId().equals(ownerId)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        // 检查被分享用户是否存在
        User userById = userMapper.getUserByUsername(username);
        if (userById == null) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        if (ownerId.equals(userById.getId())) {
            throw new BusinessException(ResponseResult.SCENE_CAN_NOT_SHARE_FOR_YOURSELF);
        }
        // 检查被分享用户是否是关联用户
        User userById1 = userMapper.getUserById(ownerId);
        if ((userById1.getParentId() == 0 && !userById.getParentId().equals(ownerId)) ||
                (userById1.getParentId() != 0 && userById1.getParentId().equals(userById.getParentId()))) {
            throw new BusinessException(ResponseResult.USER_NOT_RELATIVE);
        }
        // 申请分享组态
        Inbox inbox = new Inbox();
        inbox.setType(Constant.MsgType.EVENT);
        inbox.setCreateDate(new Date());
        inbox.setReaded(Constant.Msg.UNREADED);
        inbox.setCode(Constant.WEBSOCKETCMD.COMMON_MESSAGE);
        String content = "用户：" + userById1.getUsername() + "将组态：" + sceneById.getName() + "分享给您";
        inbox.setContent(content);
        inbox.setNeedReply(true);
        inbox.setReplyState(Constant.MSG_UNTREATED);
        inbox.setReplyUrl("/scene/share/reply");
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("srcId", ownerId);
        jsonObject.addProperty("destId", userById.getId());
        jsonObject.addProperty("sid", sid);
        inbox.setEncryptData(jsonObject.toString());
        inbox.setOwnerId(userById.getId());
        inboxMapper.saveInbox(inbox);
        simpMessagingTemplate.convertAndSendToUser(userById.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY,
                inbox);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void replyShareSceneInfo(Long uid, MsgData msgData) {
        // 检查用户是否拥有此消息
        Inbox msgInfo = inboxMapper.getMsgInfo(msgData.getMsgId());
        if (msgInfo == null || !msgInfo.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_MSG);
        }
        // 检查消息是否已经回复
        if (!Constant.MsgStatus.UNREPLY.equals(msgInfo.getReplyState())) {
            throw new BusinessException(ResponseResult.MSG_ALREADY_REPLY);
        }
        JSONObject jsonObject = JSON.parseObject(msgInfo.getEncryptData());
        if (!jsonObject.containsKey("srcId") || !jsonObject.containsKey("destId") || !jsonObject.containsKey("sid")) {
            throw new BusinessException(ResponseResult.JSON_PARSE_ERROR);
        }
        Long srcId = Long.valueOf(jsonObject.get("srcId").toString());
        Long destId = Long.valueOf(jsonObject.get("destId").toString());
        Long sid = Long.valueOf(jsonObject.get("sid").toString());

        // 检查用户是否是被分享者
        if (!destId.equals(uid)) {
            throw new BusinessException(ResponseResult.MSG_REPLY_USER_NOT_MATCH);
        }
        // 检查组态是否存在
        Scene sceneById = sceneMapper.getSceneById(Long.valueOf(sid.toString()));
        if (sceneById == null) {
            throw new BusinessException(ResponseResult.SCENE_NOT_EXISTED);
        }
        // 检查用户是否拥有此组态
        if (!sceneById.getOwnerId().equals(srcId)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }

        // 查询用户信息
        User userById = userMapper.getUserById(destId);
        User srcUser = userMapper.getUserById(srcId);
        // 分享组态
        Inbox inbox = new Inbox(srcId, Constant.MsgType.EVENT, Constant.WEBSOCKETCMD.COMMON_MESSAGE, "");
        if (msgData.getAnsCode().equals(Constant.MsgStatus.REFUSED)) {
            inboxMapper.updateInboxReply(msgData.getMsgId(), Constant.MsgStatus.REFUSED);
            String content = "用户：" + userById.getUsername() + "拒绝了您分享组态的请求，组态名：" + sceneById.getName();
            inbox.setContent(content);
            inboxMapper.saveInbox(inbox);
            simpMessagingTemplate.convertAndSendToUser(srcUser.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY,
                    inbox);
        } else if (msgData.getAnsCode().equals(Constant.MsgStatus.AGREE)) {
            sceneById.setOwnerId(uid);
            sceneById.setCreateDate(new Date());
            List<String> names = sceneMapper.getSceneNameByUid(userById.getId());
            sceneById.setName(CommonUtils.getDifferentName(sceneById.getName(), names));
            sceneById.setSceneGroupId(0L);
            sceneMapper.saveSceneInfo(sceneById);
            sceneMapper.updateSceneState(sceneById.getId(), Constant.SceneStatus.UNPUBLIC);
            // 复制组态数据
            List<Connection> sceneConnectBySid = sceneMapper.getSceneConnectBySid(sid);
            List<Variable> sceneVarBySid = sceneMapper.getSceneVarBySid(sid);
            List<AnalogAlarm> sceneAnalogAlarmBySid = sceneMapper.getSceneAnalogAlarmBySid(sid);
            List<DiscreteAlarm> sceneDiscreteAlarmBySid = sceneMapper.getSceneDiscreteAlarmBySid(sid);
            if (!sceneConnectBySid.isEmpty()) {
                sceneMapper.saveSceneConnData(sceneById.getId(), sceneConnectBySid);
            }
            if (!sceneVarBySid.isEmpty()) {
                sceneMapper.saveSceneVarData(sceneById.getId(), sceneVarBySid);
            }
            if (!sceneAnalogAlarmBySid.isEmpty()) {
                sceneMapper.saveSceneAnalogAlarmData(sceneById.getId(), sceneAnalogAlarmBySid);
            }
            if (!sceneDiscreteAlarmBySid.isEmpty()) {
                sceneMapper.saveSceneDiscreteAlarmData(sceneById.getId(), sceneDiscreteAlarmBySid);
            }

            // 保存消息，发往消息队列
            inboxMapper.updateInboxReply(msgData.getMsgId(), Constant.MsgStatus.AGREE);
            inbox.setContent("用户" + userById.getUsername() + "同意了您分享组态的请求，组态名:" + sceneById.getName());
            inboxMapper.saveInbox(inbox);
            simpMessagingTemplate.convertAndSendToUser(srcUser.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY,
                    inbox);
        } else {
            throw new BusinessException(ResponseResult.MSG_REPLY_ERROR);
        }
    }

    @Override
    public void updateSceneInfo(Long uid, Scene scene) {
        // 检查组态是否存在
        Scene sceneById = sceneMapper.getSceneById(scene.getId());
        if (sceneById == null) {
            throw new BusinessException(ResponseResult.SCENE_NOT_EXISTED);
        }
        // 检查用户是否拥有此组态
        if (!sceneById.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        // 检查组态名是否重复
        Scene sceneByUidAndSceneName = sceneMapper.getSceneByUidAndSceneName(uid, scene.getName());
        if (sceneByUidAndSceneName != null && !sceneByUidAndSceneName.getId().equals(scene.getId())) {
            throw new BusinessException(ResponseResult.SCENE_NAME_DUPLICATE);
        }
        scene.setOwnerId(sceneById.getOwnerId());
        scene.setState(sceneById.getState());
        scene.setCreateDate(sceneById.getCreateDate());
        sceneMapper.updateSceneInfo(scene);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delSceneInfo(Long uid, List<Long> sceneIds) {
        // 查重
        Set<Long> set = new HashSet<>(sceneIds);
        if (set.size() != sceneIds.size()) {
            throw new BusinessException(ResponseResult.LIST_CONTAIN_DUPLICATE_ID);
        }
        // 检查用户是否拥有这些组态
        List<Scene> sceneByUidAndSids = sceneMapper.getSceneByUidAndSids(uid, sceneIds);
        if (sceneByUidAndSids.size() != sceneIds.size()) {
            throw new BusinessException(ResponseResult.LIST_CONTAIN_ID_NOT_BELONG_TO_USER);
        }
        // 组态在运行不能删除
        for (Scene s : sceneByUidAndSids) {
            if (s.getState().compareTo(Constant.SceneStatus.PUBLIC) > 0) {
                throw new BusinessException(ResponseResult.LIST_CONTAIN_RUNNING_SCENE_ID);
            }
        }
        // 删除文件夹内的组态
        if (!sceneIds.isEmpty()) {
            sceneMapper.deleteSceneInfoAndDataBySids(sceneIds);
        }
        // 删除组态中的仪表盘
        List<Long> panelIds = panelMapper.getPanelIdsBySceneId(sceneIds);
        if (panelIds != null && !panelIds.isEmpty()) {
            panelMapper.deletePanelsByPanelIds(panelIds);
            // 删除仪表盘中地图，报表
            panelMapper.deletePanelTablesByPanelIds(panelIds);
            panelMapper.deletePanelMapsByPanelIds(panelIds);
        }
        panelMapper.deleteScenePanelsBySceneIds(sceneIds);
    }

    @Override
    public PageResult getSceneConnData(PageRequest pageRequest, Long uid, Long sid) {
        // 检查组态是否存在
        Scene sceneById = sceneMapper.getSceneById(sid);
        if (sceneById == null) {
            throw new BusinessException(ResponseResult.SCENE_NOT_EXISTED);
        }
        // 检查用户是否拥有此组态
        if (!sceneById.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<Connection> sceneConnectBySid = sceneMapper.getSceneConnectBySid(sid);
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(sceneConnectBySid));
    }

    @Override
    public PageResult getSceneVarData(PageRequest pageRequest, Long uid, Long sid, Integer mode) {
        // 检查组态是否存在
        Scene sceneById = sceneMapper.getSceneById(sid);
        if (sceneById == null) {
            throw new BusinessException(ResponseResult.SCENE_NOT_EXISTED);
        }
        // 检查用户是否拥有此组态
        if (!sceneById.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<Variable> sceneVarBySid = null;
        if (mode == null) { // 全部变量
            sceneVarBySid = sceneMapper.getSceneVarBySid(sid);
        } else if (mode == 1) { // 可作为模拟量触发变量的所有变量,bool,stringChar类型不行
            sceneVarBySid = sceneMapper.getAnalogTrigVarBySid(sid, Constant.DataTypeLen.Bool, Constant.DataTypeLen.StringChar);
        } else if (mode == 2) { // 可作为离散量触发变量的所有变量
            sceneVarBySid = sceneMapper.getDiscreteTrigVarBySid(sid, Constant.DataTypeLen.Byte, Constant.DataTypeLen.Char,
                    Constant.DataTypeLen.DInt, Constant.DataTypeLen.DWord, Constant.DataTypeLen.Real, Constant.DataTypeLen.Timer);
        } else {
            throw new BusinessException(ResponseResult.PARAM_VALUE_ILLEGAL);
        }
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(sceneVarBySid));
    }

    @Override
    public PageResult getSceneAnalogAlarm(PageRequest pageRequest, Long uid, Long sid) {
        // 检查组态是否存在
        Scene sceneById = sceneMapper.getSceneById(sid);
        if (sceneById == null) {
            throw new BusinessException(ResponseResult.SCENE_NOT_EXISTED);
        }
        // 检查用户是否拥有此组态
        if (!sceneById.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<AnalogAlarm> sceneAnalogAlarmBySid = sceneMapper.getSceneAnalogAlarmBySid(sid);
        // 去除限制值小数中多余的0
        for (AnalogAlarm a : sceneAnalogAlarmBySid) {
            a.setLimitValue(CommonUtils.removeTailZero(a.getLimitValue()));
        }
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(sceneAnalogAlarmBySid));
    }

    @Override
    public PageResult getSceneDiscreteAlarm(PageRequest pageRequest, Long uid, Long sid) {
        // 检查组态是否存在
        Scene sceneById = sceneMapper.getSceneById(sid);
        if (sceneById == null) {
            throw new BusinessException(ResponseResult.SCENE_NOT_EXISTED);
        }
        // 检查用户是否拥有此组态
        if (!sceneById.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<DiscreteAlarm> sceneDiscreteAlarmBySid = sceneMapper.getSceneDiscreteAlarmBySid(sid);
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(sceneDiscreteAlarmBySid));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void publishSceneData(Long uid, Long sceneId) {
        // 校验组态
        Scene sceneById = sceneMapper.getSceneById(sceneId);
        if (sceneById == null || !sceneById.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        if (sceneById.getState().compareTo(Constant.SceneStatus.UNPUBLIC) > 0) {
            throw new BusinessException(ResponseResult.SCENE_ALREADY_PUBLIC);
        }
        SceneData sceneData = new SceneData();
        List<Connection> sceneConnectBySid = sceneMapper.getSceneConnectBySid(sceneId);
        List<Variable> sceneVarBySid = sceneMapper.getSceneVarBySid(sceneId);
        List<AnalogAlarm> sceneAnalogAlarmBySid = sceneMapper.getSceneAnalogAlarmBySid(sceneId);
        List<DiscreteAlarm> sceneDiscreteAlarmBySid = sceneMapper.getSceneDiscreteAlarmBySid(sceneId);
        sceneData.setSceneId(sceneId);
        sceneData.setConnList(sceneConnectBySid);
        sceneData.setVarList(sceneVarBySid);
        sceneData.setAnalogAlarmList(sceneAnalogAlarmBySid);
        sceneData.setDiscreteAlarmList(sceneDiscreteAlarmBySid);
        // 校验并处理组态数据
        checkConnection(sceneData.getConnList());
        Map<Integer, Variable> varNameVar = new HashMap<>();
        checkVar(sceneData.getVarList(), sceneData.getConnList(), varNameVar);
        for (int i = 0; i < sceneVarBySid.size(); i++) {
            String[] split = sceneVarBySid.get(i).getVarAddr().split("\\s+");
            if (split.length == 2) {
                sceneVarBySid.get(i).setSubArea(1);
                if (split[0].charAt(0) == 'V') {
                    sceneVarBySid.get(i).setArea(132);
                    sceneVarBySid.get(i).setAddOffset((int) Double.parseDouble(split[1]));
                } else if (split[0].charAt(0) == 'I') {
                    sceneVarBySid.get(i).setArea(129);
                    sceneVarBySid.get(i).setAddOffset((int) Double.parseDouble(split[1]));
                } else if (split[0].charAt(0) == 'Q') {
                    sceneVarBySid.get(i).setArea(130);
                    sceneVarBySid.get(i).setAddOffset((int) Double.parseDouble(split[1]));
                } else if (split[0].charAt(0) == 'M') {
                    sceneVarBySid.get(i).setArea(131);
                    sceneVarBySid.get(i).setAddOffset((int) Double.parseDouble(split[1]));
                } else if (split[0].charAt(0) == 'C') {
                    sceneVarBySid.get(i).setArea(30);
                    sceneVarBySid.get(i).setAddOffset((int) Double.parseDouble(split[1]));
                } else if (split[0].charAt(0) == 'T') {
                    sceneVarBySid.get(i).setArea(31);
                    sceneVarBySid.get(i).setAddOffset((int) Double.parseDouble(split[1]));
                } else {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
                if (split[1].contains(".")) {
                    String[] arr = split[1].split("\\.");
                    if (arr[1].length() != 1) {
                        throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                    }
                    int i1 = 0;
                    try {
                        i1 = Integer.parseInt(arr[1]);
                    } catch (NumberFormatException e) {
                        throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                    }
                    sceneVarBySid.get(i).setBitOffset(i1);
                } else {
                    sceneVarBySid.get(i).setBitOffset(-1);
                }
            } else if (split.length == 4) {
                sceneVarBySid.get(i).setSubArea(Integer.valueOf(split[1]));
                sceneVarBySid.get(i).setArea(133);
                double v = Double.parseDouble(split[3]);
                // 整数部分
                int intValue = (int) v;
                // 小数部分（0-7），乘以10取整
                int decimalValue = (int) (v - intValue) * 10;
                sceneVarBySid.get(i).setAddOffset(intValue);
                if (split[3].contains(".")) {
                    sceneVarBySid.get(i).setBitOffset(decimalValue);
                } else {
                    sceneVarBySid.get(i).setBitOffset(-1);
                }
            } else {
                throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
            }
        }
//        if (sceneData.getAnalogAlarmList().size() + sceneData.getDiscreteAlarmList().size() == 0) {
//            throw new BusinessException(ResponseResult.ANALOG_DISCRETE_ALARM_BOTH_EMPTY);
//        }
        checkAnalogAlarm(sceneData.getAnalogAlarmList(), varNameVar);
        checkDiscreteAlarm(sceneData.getDiscreteAlarmList(), varNameVar);
        if (sceneVarBySid.isEmpty()) {
            throw new BusinessException(ResponseResult.VARIABLE_CANNOT_BE_EMPTY);
        }
        // 更新组态变量地址相关参数
        sceneMapper.updateSceneVarAddr(sceneData.getSceneId(), sceneVarBySid);
        // 修改组态状态
        sceneMapper.updateSceneState(sceneData.getSceneId(), Constant.SceneStatus.PUBLIC);
    }

//    // 获取文件夹下所有组态信息，包含递归子文件夹下的
//    private List<Scene> getGroupScenes(Long uid, Long gid) {
//        List<Scene> scenes = new ArrayList<>();
//        List<SceneGroup> sceneGroupByUidAndPid = sceneMapper.getSceneGroupByUidAndPid(uid, gid);
//        List<Scene> sceneByUidAndGid = sceneMapper.getSceneByUidAndGid(uid, gid);
//        scenes.addAll(sceneByUidAndGid);
//        List<Scene> tmp = null;
//        for (SceneGroup s : sceneGroupByUidAndPid) {
//            tmp = getAllScenesFromSceneGroup(scenes, s);
//            scenes.addAll(tmp);
//        }
//        return scenes;
//    }

    @Override
    public void saveSceneGroup(Long uid, Long pid, String name) {
        // 检查pid是否有效,pid=0为顶层目录
        int pRank = 0;
        if (pid > 0) {
            SceneGroup sceneGroupByGid = sceneMapper.getSceneGroupByGid(pid);
            if (sceneGroupByGid == null || !sceneGroupByGid.getOwnerId().equals(uid)) {
                throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE_FOLDER);
            }
            // 组态目录层级不超过3级
            pRank = sceneGroupByGid.getRank();
            if (pRank >= 3) {
                throw new BusinessException(ResponseResult.SCENE_GROUP_RANK_EXCEED_LIMIT);
            }
        }
        // 检查文件夹名字是否重复
        List<String> allSceneGroupNameByUid = sceneMapper.getAllSceneGroupNameByUid(uid);
        if (allSceneGroupNameByUid.contains(name)) {
            throw new BusinessException(ResponseResult.SCENE_GROUP_NAME_DUPLICATE);
        }
        sceneMapper.saveSceneGroup(uid, pid, name, pRank + 1);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSceneGroup(Long uid, Long pid, Long gid, String name) {
        // 检查pid是否有效,pid=0为顶层目录
        int pRank = 0;
        if (pid != 0L) {
            SceneGroup sceneGroupByGid = sceneMapper.getSceneGroupByGid(pid);
            if (sceneGroupByGid == null || !sceneGroupByGid.getOwnerId().equals(uid)) {
                throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE_FOLDER);
            }
            // 组态目录层级不超过3级
            pRank = sceneGroupByGid.getRank();
            if (pRank >= 3) {
                throw new BusinessException(ResponseResult.SCENE_GROUP_RANK_EXCEED_LIMIT);
            }
        }
        // 检查gid是否有效
        SceneGroup sceneGroupByGid1 = sceneMapper.getSceneGroupByGid(gid);
        if (sceneGroupByGid1 == null || !sceneGroupByGid1.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE_FOLDER);
        }
        // 检查文件夹名字是否重复
        List<String> allSceneGroupNameByUid = sceneMapper.getAllSceneGroupNameByUid(uid);
        allSceneGroupNameByUid.remove(sceneGroupByGid1.getName());
        if (allSceneGroupNameByUid.contains(name)) {
            throw new BusinessException(ResponseResult.SCENE_GROUP_NAME_DUPLICATE);
        }

        // 目录层次发生改变
        if (pRank + 1 != sceneGroupByGid1.getRank()) {
            // 查询子文件夹及组态集合
            SceneGroup sceneGroupByGroupId = sceneMapper.getSceneGroupByGroupId(uid, gid, "", "");

            // 检查需要移动的目录层级+父目录层级是否会超过三层
            int maxLayerNum = sceneGroupByGroupId.getRank() - 1;
            List<Long> ids = new ArrayList<>();
            Queue<SceneGroup> sceneGroups = new LinkedList<>();
            sceneGroups.add(sceneGroupByGroupId);
            ids.add(sceneGroupByGroupId.getId());
            while (!sceneGroups.isEmpty()) {
                maxLayerNum++;
                int size = sceneGroups.size();
                for (int i = 0; i < size; i++) {
                    SceneGroup poll = sceneGroups.poll();
                    if (poll != null && poll.getSceneGroups() != null && !poll.getSceneGroups().isEmpty()) {
                        for (int j = 0; j < poll.getSceneGroups().size(); j++) {
                            sceneGroups.add(poll.getSceneGroups().get(j));
                            ids.add(poll.getSceneGroups().get(j).getId());
                        }
                    }
                }
            }
            if (maxLayerNum - sceneGroupByGroupId.getRank() + pRank >= 3) {
                throw new BusinessException(ResponseResult.SCENE_GROUP_LAYER_MOVE_EXCEED_LIMIT);
            }
            // 修改移动的文件夹及其子文件夹的rank
            sceneMapper.updateSceneGroupRank(ids, pRank + 1 - sceneGroupByGroupId.getRank());
        }
        sceneMapper.updateSceneGroup(pid, gid, name);
    }

//    private int getMaxLayerNum(SceneGroup sceneGroup, int layerNum) {
//        if (sceneGroup.getSceneGroups() == null || sceneGroup.getSceneGroups().isEmpty()) {
//            return layerNum;
//        }
//        int res = layerNum;
//        for (int i = 0; i < sceneGroup.getSceneGroups().size(); i++) {
//            res = Math.max(res, getMaxLayerNum(sceneGroup.getSceneGroups().get(i), layerNum + 1));
//        }
//        return res;
//    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delSceneGroup(Long uid, Long gid) {
        // 检查gid是否有效
        SceneGroup sceneGroupByGid = sceneMapper.getSceneGroupByGid(gid);
        if (sceneGroupByGid == null || !sceneGroupByGid.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE_FOLDER);
        }
        // 查询子文件夹及组态集合
        SceneGroup sceneGroupByGroupId = sceneMapper.getSceneGroupByGroupId(uid, gid, "", "");
        // 获取该文件夹下所有子文件(包括该文件夹）
        List<SceneGroup> allChildSceneGroup = getAllChildSceneGroup(sceneGroupByGroupId);
        // 获取文件夹下所有组态文件
        List<Scene> groupScenes = getAllGroupScenes(sceneGroupByGroupId);
        List<Long> sceneIds = new ArrayList<>();
        for (Scene s : groupScenes) {
            // 不能删除正在运行的组态
            if (s.getState().compareTo(Constant.SceneStatus.PUBLIC) > 0) {
                throw new BusinessException(ResponseResult.RUNNING_SCENE_IN_THIS_FOLDER);
            }
            sceneIds.add(s.getId());
        }
        // 删除文件夹
        if (!allChildSceneGroup.isEmpty()) {
            sceneMapper.delSceneGroup(allChildSceneGroup);
        }
        // 删除文件夹内的组态
        if (!sceneIds.isEmpty()) {
            sceneMapper.deleteSceneInfoAndDataBySids(sceneIds);
        }
        // 删除组态中的仪表盘
        if (!sceneIds.isEmpty()) {
            List<Long> panelIds = panelMapper.getPanelIdsBySceneId(sceneIds);
            panelMapper.deleteScenePanelsBySceneIds(sceneIds);
            if (panelIds != null && !panelIds.isEmpty()) {
                panelMapper.deletePanelsByPanelIds(panelIds);
                // 删除仪表盘中地图，报表
                panelMapper.deletePanelTablesByPanelIds(panelIds);
                panelMapper.deletePanelMapsByPanelIds(panelIds);
            }
        }
    }

    private List<Scene> getAllGroupScenes(SceneGroup sceneGroup) {
        // 加上文件夹直属组态
        List<Scene> allScene = new ArrayList<>(sceneGroup.getScenes());
        // 递归加上子文件组态
        for (SceneGroup sg : sceneGroup.getSceneGroups()) {
            List<Scene> childScenes = getAllGroupScenes(sg);
            if (childScenes.size() != 0) {
                allScene.addAll(childScenes);
            }
        }
        return allScene;
    }

    @Override
    public PageResult getDiffGroupSceneInfo(PageRequest pageRequest, Long uid, Long gid, String sort, Date startDate, Date endDate, String search) {
        // 校验sort字段
        if (StringUtils.hasLength(sort)) {
            List<String> list = Arrays.asList(SCENESORTFIELD);
            String[] s = sort.split("\\s+");
            if (s.length != 2 || !list.contains(s[0]) || !"desc".equalsIgnoreCase(s[1])
                    && !"asc".equalsIgnoreCase(s[1])) {
                throw new BusinessException(ResponseResult.SORT_FIELD_FORMAT_ERROR);
            }
        }
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        if (gid != null && gid > Constant.UNGROUPED) {
            // 检查用户是否拥有组态文件夹
            SceneGroup sceneGroupByGid = sceneMapper.getSceneGroupByGid(gid);
            if (sceneGroupByGid == null || !sceneGroupByGid.getOwnerId().equals(uid)) {
                throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE_FOLDER);
            }
        }
        // 校验起始时间和结束时间
        if (startDate != null && endDate != null && startDate.compareTo(endDate) > 0) {
            throw new BusinessException(ResponseResult.START_DATE_LARGER_THAN_END_DATE);
        }

        List<Scene> allSceneInfo = sceneMapper.getSceneInfo(uid, gid, sort, startDate, endDate, search);
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(allSceneInfo));
    }

    @Override
    public Connection getOneSceneConnData(Long uid, Long connectId) {
        // 检查是否拥有连接id
        Connection sceneConnectByUidAndConnectId = sceneMapper.getSceneConnectByUidAndConnectId(uid, connectId);
        if (sceneConnectByUidAndConnectId == null) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_CONNECT);
        }
        return sceneConnectByUidAndConnectId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveSceneConnData(Long uid, Connection connection) {
        // 检查是否拥有此组态id
        Scene sceneByUidAndSid = sceneMapper.getSceneByUidAndSid(uid, connection.getSceneId());
        if (sceneByUidAndSid == null) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        checkSceneState(sceneByUidAndSid);
        List<Connection> sceneConnectInfoBySid = sceneMapper.getSceneConnectInfoBySid(connection.getSceneId());
        List<Integer> connIds = new ArrayList<>();
        List<String> names = new ArrayList<>();
//        List<Integer> driveTypes = new ArrayList<>();
        for (Connection c : sceneConnectInfoBySid) {
            connIds.add(c.getConnectNo());
            names.add(c.getName());
//            driveTypes.add(c.getDriveType());
        }
        // connId,name,driveTypes判重
        if (connIds.contains(connection.getConnectNo())) {
            throw new BusinessException(ResponseResult.CONNECT_ID_FIELD_REPEAT);
        }
        if (names.contains(connection.getName())) {
            throw new BusinessException(ResponseResult.CONNECT_NAME_FIELD_REPEAT);
        }
//        if (driveTypes.contains(connection.getDriveType())) {
//            throw new BusinessException(ResponseResult.OBJECT_DUPLICATE, "对象类型：组态连接驱动");
//        }
        if (!connection.getDriveType().equals(Constant.ProtocolValue.GATEWAY)) {
            throw new BusinessException(ResponseResult.CONNECT_DRIVE_TYPE_UNSUPPORTED);
        }
        if (connection.getDriveType().equals(Constant.ProtocolValue.GATEWAY)) {
            if (!"以太网".equals(connection.getPort())) {
                throw new BusinessException(ResponseResult.CONNECT_PORT_ILLEGAL);
            }
        }
        connection.setSceneId(connection.getSceneId());
        sceneMapper.saveSceneConnect(connection);
        // 修改组态状态
        sceneMapper.updateSceneState(connection.getSceneId(), Constant.SceneStatus.UNPUBLIC);
//         增加组态连接配置设备（为-1）
//        sceneMapper.saveSceneDeviceByConnIdAndDeviceId(connection.getId(), Constant.SCENE_DEVICE_IS_EMPTY);
    }

    /**
     * 校验组态状态，禁止修改在运行组态
     *
     * @param scene
     * @return: void
     */
    private void checkSceneState(Scene scene) {
        if (scene.getState().compareTo(Constant.SceneStatus.PUBLIC) > 0) {
            throw new BusinessException(ResponseResult.RUNNING_SCENE_CAN_NOT_UPDATE);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSceneConnData(Long uid, Connection connection) {
        // 检查是否拥有连接id
        Scene sceneByUidAndConnId = sceneMapper.getSceneByUidAndConnId(uid, connection.getId());
        if (sceneByUidAndConnId == null) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_CONNECT);
        }
        checkSceneState(sceneByUidAndConnId);
        List<Connection> sceneConnectInfoBySid = sceneMapper.getSceneConnectInfoBySid(sceneByUidAndConnId.getId());
        List<Integer> connIds = new ArrayList<>();
        List<String> names = new ArrayList<>();
//        List<Integer> driveTypes = new ArrayList<>();
        Connection con = null;
        for (Connection c : sceneConnectInfoBySid) {
            connIds.add(c.getConnectNo());
            names.add(c.getName());
//            driveTypes.add(c.getDriveType());
            if (connection.getId().equals(c.getId())) {
                con = c;
            }
        }
        // 去掉正在修改的连接，便于判重
        if (con != null) {
            connIds.remove(con.getConnectNo());
            names.remove(con.getName());
//            driveTypes.remove(con.getDriveType());
        }
        // connId,name,driveTypes判重
        if (connIds.contains(connection.getConnectNo())) {
            throw new BusinessException(ResponseResult.CONNECT_ID_FIELD_REPEAT);
        }
        if (names.contains(connection.getName())) {
            throw new BusinessException(ResponseResult.CONNECT_NAME_FIELD_REPEAT);
        }
//        if (driveTypes.contains(connection.getDriveType())) {
//            throw new BusinessException("组态连接驱动", ResponseResult.OBJECT_DUPLICATE);
//        }
        if (!connection.getDriveType().equals(Constant.ProtocolValue.GATEWAY)) {
            throw new BusinessException(ResponseResult.CONNECT_DRIVE_TYPE_UNSUPPORTED);
        }
        if (connection.getDriveType().equals(Constant.ProtocolValue.GATEWAY)) {
            if (!"以太网".equals(connection.getPort())) {
                throw new BusinessException(ResponseResult.CONNECT_PORT_ILLEGAL);
            }
        }
        connection.setSceneId(sceneByUidAndConnId.getId());
        sceneMapper.updateSceneConnect(connection);
        // 修改组态状态
        sceneMapper.updateSceneState(sceneByUidAndConnId.getId(), Constant.SceneStatus.UNPUBLIC);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delSceneConnData(Long uid, List<Long> connIds) {
        // 校验是否有重复id
        Set<Long> set = new HashSet<>(connIds);
        if (set.size() != connIds.size()) {
            throw new BusinessException(ResponseResult.LIST_CONTAIN_DUPLICATE_ID);
        }
        // 校验第一个id的组态
        Scene sceneByConnId = sceneMapper.getSceneByConnId(connIds.get(0));
        if (sceneByConnId == null || !sceneByConnId.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_CONNECT);
        }
        // 校验组态状态
        checkSceneState(sceneByConnId);

        // 校验其他id
        List<Long> sceneConnIdBySceneId = sceneMapper.getSceneConnIdBySceneId(sceneByConnId.getId());
        for (Long id : connIds) {
            if (!sceneConnIdBySceneId.contains(id)) {
                throw new BusinessException(ResponseResult.CONNECT_ID_BELONG_TO_DIFF_SCENE);
            }
        }
        if (!connIds.isEmpty()) {
            sceneMapper.delSceneConnect(connIds);
        }
        // 修改组态状态
        sceneMapper.updateSceneState(sceneByConnId.getId(), Constant.SceneStatus.UNPUBLIC);
        // 删除组态连接
        sceneMapper.deleteSceneConnections(connIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveSceneVarData(Long uid, Variable v) {
        // 检查是否拥有此组态id
        Scene sceneByUidAndSid = sceneMapper.getSceneByUidAndSid(uid, v.getSceneId());
        if (sceneByUidAndSid == null) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        checkSceneState(sceneByUidAndSid);

        // 限制变量数量在10000以内
        List<Variable> sceneVarBySid = sceneMapper.getSceneVarBySid(v.getSceneId());
        List<Connection> sceneConnectInfoBySid = sceneMapper.getSceneConnectInfoBySid(v.getSceneId());
        if (sceneVarBySid.size() >= 10000) {
            throw new BusinessException(ResponseResult.VARIABLE_COUNT_TOO_MUCH);
        }
        List<Integer> varIds = new ArrayList<>();
        List<String> varNames = new ArrayList<>();
        List<Integer> connNos = new ArrayList<>();
        Map<Integer, Integer> connNameProtocol = new HashMap<>();
        for (Variable var : sceneVarBySid) {
            varIds.add(var.getVarNo());
            varNames.add(var.getName());
        }
        for (Connection c : sceneConnectInfoBySid) {
            connNos.add(c.getConnectNo());
            connNameProtocol.put(c.getConnectNo(), c.getDriveType());
        }
        // id,name判重
        if (varIds.contains(v.getVarNo())) {
            throw new BusinessException(ResponseResult.VARIABLE_ID_FIELD_REPEAT);
        }
        if (varNames.contains(v.getName())) {
            throw new BusinessException(ResponseResult.VARIABLE_NAME_FIELD_REPEAT);
        }
        // 检查变量对应的连接名是否存在
        if (!connNos.contains(v.getConnectNo())) {
            throw new BusinessException(ResponseResult.CONNECT_NAME_INVALID);
        }
        // 校验数据类型,长度，地址,按不同协议处理
        // 合信网关协议
        if (connNameProtocol.get(v.getConnectNo()).equals(Constant.ProtocolValue.GATEWAY)) {
            // 通过连接名获取协议，通过协议获取数据类型
            checkUDPPPI(v, connNameProtocol);
        } else {
            throw new BusinessException(ResponseResult.CONNECT_PROTOCOL_ONLY_SUPPORT_GETWAY);
        }
        v.setSceneId(v.getSceneId());
        sceneMapper.saveSceneVariable(v);
        // 修改组态状态
        sceneMapper.updateSceneState(v.getSceneId(), Constant.SceneStatus.UNPUBLIC);

    }

    /**
     * 校验UDP PPI变量（合信网关协议）
     *
     * @param v
     * @param connNoProtocol
     * @return: void
     */
    private void checkUDPPPI(Variable v, Map<Integer, Integer> connNoProtocol) {
        List<Integer> dataTypeByProtocol = getDataTypeByDriveType(connNoProtocol.get(v.getConnectNo()));
        if (!dataTypeByProtocol.contains(v.getDataType())) {
            throw new BusinessException(ResponseResult.VARIABLE_DATATYPE_INVALID);
        }
        // 校验数据长度,地址
        String varAddr = v.getVarAddr();
        if (varAddr == null) {
            throw new BusinessException(ResponseResult.VARIABLE_ADDR_CANNOT_BE_EMPTY);
        }
        String[] split = varAddr.split("\\s+");
        if (Constant.DataTypeLen.Char.equals(v.getDataType())) {
            if (!v.getLen().equals(1)) {
                throw new BusinessException(ResponseResult.VARIABLE_LEN_ERROR);
            }
            if (split.length == 2) {
                // 将不同地址对应的最大值存入map,最小值0
                Map<String, Integer> map = new HashMap<>();
                map.put("VB", 65535);
                map.put("IB", 32767);
                map.put("QB", 32767);
                map.put("MB", 32767);
                Integer maxVal = map.get(split[0]);
                if (maxVal == null || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > maxVal
                        || Integer.parseInt(split[1]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else {
                throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
            }
        } else if (Constant.DataTypeLen.Byte.equals(v.getDataType())) {
            if (!v.getLen().equals(1)) {
                throw new BusinessException(ResponseResult.VARIABLE_LEN_ERROR);
            }
            if (split.length == 2) {
                // 将不同地址对应的最大值存入map,最小值0
                Map<String, Integer> map = new HashMap<>();
                map.put("VB", 65535);
                map.put("IB", 32767);
                map.put("QB", 32767);
                map.put("MB", 32767);
                Integer maxVal = map.get(split[0]);
                if (maxVal == null || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > maxVal
                        || Integer.parseInt(split[1]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else if (split.length == 4) {
                if (!"DB".equals(split[0]) || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > 254 ||
                        Integer.parseInt(split[1]) < 0 || !"DBB".equals(split[2]) || !CommonUtils.isDigit(split[3])
                        || Integer.parseInt(split[3]) > 65535 || Integer.parseInt(split[3]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else {
                throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
            }
        } else if (Constant.DataTypeLen.Int.equals(v.getDataType())) {
            if (!v.getLen().equals(2)) {
                throw new BusinessException(ResponseResult.VARIABLE_LEN_ERROR);
            }
            if (split.length == 2) {
                // 将不同地址对应的最大值存入map,最小值0
                Map<String, Integer> map = new HashMap<>();
                map.put("VW", 65534);
                map.put("IW", 32766);
                map.put("QW", 32766);
                map.put("MW", 32766);
                map.put("C", 32766);
                Integer maxVal = map.get(split[0]);
                if (maxVal == null || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > maxVal
                        || Integer.parseInt(split[1]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else if (split.length == 4) {
                if (!"DB".equals(split[0]) || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > 254 ||
                        Integer.parseInt(split[1]) < 0 || !"DBW".equals(split[2]) || !CommonUtils.isDigit(split[3])
                        || Integer.parseInt(split[3]) > 65535 || Integer.parseInt(split[3]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else {
                throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
            }
        } else if (Constant.DataTypeLen.Word.equals(v.getDataType())) {
            if (!v.getLen().equals(2)) {
                throw new BusinessException(ResponseResult.VARIABLE_LEN_ERROR);
            }
            if (split.length == 2) {
                // 将不同地址对应的最大值存入map,最小值0
                Map<String, Integer> map = new HashMap<>();
                map.put("VW", 65534);
                map.put("IW", 32766);
                map.put("QW", 32766);
                map.put("MW", 32766);
                Integer maxVal = map.get(split[0]);
                if (maxVal == null || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > maxVal
                        || Integer.parseInt(split[1]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else if (split.length == 4) {
                if (!"DB".equals(split[0]) || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > 254 ||
                        Integer.parseInt(split[1]) < 0 || !"DBW".equals(split[2]) || !CommonUtils.isDigit(split[3])
                        || Integer.parseInt(split[3]) > 65534 || Integer.parseInt(split[3]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else {
                throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
            }
        } else if (Constant.DataTypeLen.DInt.equals(v.getDataType())) {
            if (!v.getLen().equals(4)) {
                throw new BusinessException(ResponseResult.VARIABLE_LEN_ERROR);
            }
            if (split.length == 2) {
                // 将不同地址对应的最大值存入map,最小值0
                Map<String, Integer> map = new HashMap<>();
                map.put("VD", 65532);
                map.put("ID", 32764);
                map.put("QD", 32764);
                map.put("MD", 32764);
                Integer maxVal = map.get(split[0]);
                if (maxVal == null || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > maxVal
                        || Integer.parseInt(split[1]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else if (split.length == 4) {
                if (!"DB".equals(split[0]) || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > 254 ||
                        Integer.parseInt(split[1]) < 0 || !"DBD".equals(split[2]) || !CommonUtils.isDigit(split[3])
                        || Integer.parseInt(split[3]) > 65532 || Integer.parseInt(split[3]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else {
                throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
            }
        } else if (Constant.DataTypeLen.DWord.equals(v.getDataType())) {
            if (!v.getLen().equals(4)) {
                throw new BusinessException(ResponseResult.VARIABLE_LEN_ERROR);
            }
            if (split.length == 2) {
                // 将不同地址对应的最大值存入map,最小值0
                Map<String, Integer> map = new HashMap<>();
                map.put("VD", 65532);
                map.put("ID", 32764);
                map.put("QD", 32764);
                map.put("MD", 32764);
                Integer maxVal = map.get(split[0]);
                if (maxVal == null || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > maxVal
                        || Integer.parseInt(split[1]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else if (split.length == 4) {
                if (!"DB".equals(split[0]) || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > 254 ||
                        Integer.parseInt(split[1]) < 0 || !"DBD".equals(split[2]) || !CommonUtils.isDigit(split[3])
                        || Integer.parseInt(split[3]) > 65532 || Integer.parseInt(split[3]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else {
                throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
            }
        } else if (Constant.DataTypeLen.Real.equals(v.getDataType())) {
            if (!v.getLen().equals(4)) {
                throw new BusinessException(ResponseResult.VARIABLE_LEN_ERROR);
            }
            if (split.length == 2) {
                // 将不同地址对应的最大值存入map,最小值0
                Map<String, Integer> map = new HashMap<>();
                map.put("VD", 65532);
                map.put("ID", 32764);
                map.put("QD", 32764);
                map.put("MD", 32764);
                Integer maxVal = map.get(split[0]);
                if (maxVal == null || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > maxVal
                        || Integer.parseInt(split[1]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else if (split.length == 4) {
                if (!"DB".equals(split[0]) || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > 254 ||
                        Integer.parseInt(split[1]) < 0 || !"DBD".equals(split[2]) || !CommonUtils.isDigit(split[3])
                        || Integer.parseInt(split[3]) > 65532 || Integer.parseInt(split[3]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else {
                throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
            }
        } else if (Constant.DataTypeLen.Bool.equals(v.getDataType())) {
            if (!v.getLen().equals(1)) {
                throw new BusinessException(ResponseResult.VARIABLE_LEN_ERROR);
            }
            if (split.length == 2) {
                // 将不同地址对应的最大值存入map,最小值0
                Map<String, Integer> map = new HashMap<>();
                map.put("V", 65535);
                map.put("I", 32767);
                map.put("Q", 32767);
                map.put("M", 32767);
                Integer maxVal = map.get(split[0]);
                if (maxVal != null) {
                    String[] split1 = split[1].split("\\.");
                    if (split1.length != 2) {
                        throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                    } else {
                        try {
                            if (Integer.parseInt(split1[0]) > maxVal || Integer.parseInt(split1[1]) < 0
                                    || Integer.parseInt(split1[1]) < 0 || Integer.parseInt(split1[1]) > 7) {
                                throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                            }
                        } catch (NumberFormatException e) {
                            throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                        }
                    }
                } else {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else if (split.length == 4) {
                if (!"DB".equals(split[0]) || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > 254 ||
                        Integer.parseInt(split[1]) < 0 || !"DBX".equals(split[2])) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                } else {
                    String[] split1 = split[3].split("\\.");
                    if (split1.length != 2 || !CommonUtils.isDigit(split1[0]) || Integer.parseInt(split1[0]) > 65535 ||
                            Integer.parseInt(split1[0]) < 0 || !CommonUtils.isDigit(split1[1]) || Integer.parseInt(split1[1]) > 7
                            || Integer.parseInt(split1[1]) > 0) {
                        throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                    }
                }
            } else {
                throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
            }
        } else if (Constant.DataTypeLen.StringChar.equals(v.getDataType())) {
            if (!v.getLen().equals(10)) {
                throw new BusinessException(ResponseResult.VARIABLE_LEN_ERROR);
            }
            if (split.length == 2) {
                // 将不同地址对应的最大值存入map,最小值0
                Map<String, Integer> map = new HashMap<>();
                map.put("VB", 65536);
                map.put("IB", 32768);
                map.put("QB", 32768);
                map.put("MB", 32768);
                Integer maxVal = map.get(split[0]);
                if (maxVal == null || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > maxVal
                        || Integer.parseInt(split[1]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else if (split.length == 4) {
                if (!"DB".equals(split[0]) || !CommonUtils.isDigit(split[1]) || Integer.parseInt(split[1]) > 254 ||
                        Integer.parseInt(split[1]) < 0 || !"DBB".equals(split[2]) || !CommonUtils.isDigit(split[3])
                        || Integer.parseInt(split[3]) > 65536 || Integer.parseInt(split[3]) < 0) {
                    throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
                }
            } else {
                throw new BusinessException(ResponseResult.VARIABLE_ADDR_ERROR);
            }
        } else if (Constant.DataTypeLen.Timer.equals(v.getDataType())) {
            if (!v.getLen().equals(4)) {
                throw new BusinessException(ResponseResult.VARIABLE_LEN_ERROR);
            }
            if (split.length != 2 || !"T".equals(split[0]) || !CommonUtils.isDigit(split[1])
                    || Integer.parseInt(split[1]) > 32764 || Integer.parseInt(split[1]) < 0) {
                throw new BusinessException(ResponseResult.VARIABLE_LEN_ERROR);
            }
        }
    }

    @Override
    public Variable getOneSceneVarData(Long uid, Long varId) {
        // 检查用户是否拥有变量
        Variable sceneVariableByUidAndVarId = sceneMapper.getSceneVariableByUidAndVarId(uid, varId);
        if (sceneVariableByUidAndVarId == null) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_VAR);
        }
        return sceneVariableByUidAndVarId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSceneVarData(Long uid, Variable v) {
        // 检查用户是否拥有变量
        Scene sceneByUidAndVarId = sceneMapper.getSceneByUidAndVarId(uid, v.getId());
        if (sceneByUidAndVarId == null) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_VAR);
        }
        checkSceneState(sceneByUidAndVarId);

        // 获取组态所有变量
        List<Variable> sceneVarBySid = sceneMapper.getSceneVarBySid(sceneByUidAndVarId.getId());
        List<Connection> sceneConnectBySid = sceneMapper.getSceneConnectBySid(sceneByUidAndVarId.getId());
        List<Integer> varIds = new ArrayList<>();
        List<String> varNames = new ArrayList<>();
        List<Integer> connNos = new ArrayList<>();
        Map<Integer, Integer> connNameProtocol = new HashMap<>();
        Variable varTmp = new Variable();
        for (Variable var : sceneVarBySid) {
            varIds.add(var.getVarNo());
            varNames.add(var.getName());
            if (var.getId().equals(v.getId())) {
                varTmp = var;
            }
        }
        // 去掉要修改的变量，便于判重
        sceneVarBySid.remove(varTmp);
        varIds.remove(varTmp.getVarNo());
        varNames.remove(varTmp.getName());
        for (Connection c : sceneConnectBySid) {
            connNos.add(c.getConnectNo());
            connNameProtocol.put(c.getConnectNo(), c.getDriveType());
        }
        // id,name判重
        if (varIds.contains(v.getVarNo())) {
            throw new BusinessException(ResponseResult.VARIABLE_ID_FIELD_REPEAT);
        }
        if (varNames.contains(v.getName())) {
            throw new BusinessException(ResponseResult.VARIABLE_NAME_FIELD_REPEAT);
        }
        // 检查变量对应的连接名是否存在
        if (!connNos.contains(v.getConnectNo())) {
            throw new BusinessException(ResponseResult.CONNECT_NAME_INVALID);
        }
        // 校验数据类型,长度，地址,按不同协议处理
        // 合信网关协议
        if (connNameProtocol.get(v.getConnectNo()).equals(Constant.ProtocolValue.GATEWAY)) {
            // 通过连接名获取协议，通过协议获取数据类型
            checkUDPPPI(v, connNameProtocol);
        } else {
            throw new BusinessException(ResponseResult.CONNECT_PROTOCOL_ONLY_SUPPORT_GETWAY);
        }
        sceneMapper.updateSceneVariable(v);
        // 修改组态状态
        sceneMapper.updateSceneState(sceneByUidAndVarId.getId(), Constant.SceneStatus.UNPUBLIC);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delSceneVarData(Long uid, List<Long> varIds) {
        // 校验是否有重复id
        Set<Long> set = new HashSet<>(varIds);
        if (set.size() != varIds.size()) {
            throw new BusinessException(ResponseResult.LIST_CONTAIN_DUPLICATE_ID);
        }
        // 校验第一个id的组态
        Scene sceneByVarId = sceneMapper.getSceneByVarId(varIds.get(0));
        if (sceneByVarId == null || !sceneByVarId.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_VAR);
        }
        // 校验组态状态
        checkSceneState(sceneByVarId);

        // 校验其他id
        List<Long> sceneVarIdBySceneId = sceneMapper.getSceneVarIdBySceneId(sceneByVarId.getId());
        for (Long id : varIds) {
            if (!sceneVarIdBySceneId.contains(id)) {
                throw new BusinessException(ResponseResult.CONNECT_ID_BELONG_TO_DIFF_SCENE);
            }
        }
        if (!varIds.isEmpty()) {
            sceneMapper.delSceneVariable(varIds);
        }
        // 修改组态状态
        sceneMapper.updateSceneState(sceneByVarId.getId(), Constant.SceneStatus.UNPUBLIC);
    }

    @Override
    public AnalogAlarm getOneSceneAnalogData(Long uid, Long analogId) {
        // 检查用户是否拥有模拟量
        AnalogAlarm sceneAnalogByUidAndAnalogId = sceneMapper.getSceneAnalogByUidAndAnalogId(uid, analogId);
        if (sceneAnalogByUidAndAnalogId == null) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_ANALOG_ALARM);
        }
        sceneAnalogByUidAndAnalogId.setLimitValue(CommonUtils.removeTailZero(sceneAnalogByUidAndAnalogId.getLimitValue()));
        return sceneAnalogByUidAndAnalogId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveSceneAnalogData(Long uid, AnalogAlarm analog) {
        // 检查是否拥有此组态id
        Scene sceneByUidAndSid = sceneMapper.getSceneByUidAndSid(uid, analog.getSceneId());
        if (sceneByUidAndSid == null) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        checkSceneState(sceneByUidAndSid);

        List<AnalogAlarm> sceneAnalogAlarmBySid = sceneMapper.getSceneAnalogAlarmBySid(analog.getSceneId());
        List<Variable> sceneVarBySid = sceneMapper.getSceneVarBySid(analog.getSceneId());
        if (sceneAnalogAlarmBySid.size() >= 10000) {
            throw new BusinessException(ResponseResult.ANALOG_ALARM_TOO_MUCH);
        }
        List<Integer> analogIds = new ArrayList<>();
        Map<Integer, Variable> variableMap = new HashMap<>();
        for (AnalogAlarm a : sceneAnalogAlarmBySid) {
            analogIds.add(a.getAlarmNo());
        }
        for (Variable v : sceneVarBySid) {
            variableMap.put(v.getVarNo(), v);
        }
        // alarm id判重
        if (analogIds.contains(analog.getAlarmNo())) {
            throw new BusinessException(ResponseResult.ANALOG_ALARM_ID_REPEAT);
        }
        // 检查变量限制值格式
        if (!CommonUtils.isFloat(analog.getLimitValue())) {
            throw new BusinessException(ResponseResult.VARIABLE_LIMIT_VALUE_FORMAT_ERROR);
        }
        checkAnalog(variableMap, analog);
        analog.setSceneId(analog.getSceneId());
        sceneMapper.saveSceneAnalog(analog);
        // 修改组态状态
        sceneMapper.updateSceneState(analog.getSceneId(), Constant.SceneStatus.UNPUBLIC);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSceneAnalogData(Long uid, AnalogAlarm analog) {
        // 检查用户是否拥有模拟量
        Scene sceneByUidAndAnalogId = sceneMapper.getSceneByUidAndAnalogId(uid, analog.getId());
        if (sceneByUidAndAnalogId == null) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_ANALOG_ALARM);
        }

        checkSceneState(sceneByUidAndAnalogId);

        List<AnalogAlarm> sceneAnalogAlarmBySid = sceneMapper.getSceneAnalogAlarmBySid(sceneByUidAndAnalogId.getId());
        List<Variable> sceneVarBySid = sceneMapper.getSceneVarBySid(sceneByUidAndAnalogId.getId());
        List<Integer> analogIds = new ArrayList<>();
        Map<Integer, Variable> variableMap = new HashMap<>();
        AnalogAlarm ana = null;
        for (AnalogAlarm a : sceneAnalogAlarmBySid) {
            analogIds.add(a.getAlarmNo());
            if (a.getId().equals(analog.getId())) {
                ana = a;
            }
        }
        // 删除正在修改的模拟量，便于判重
        sceneAnalogAlarmBySid.remove(ana);
        if (ana != null) {
            analogIds.remove(ana.getAlarmNo());
        }
        for (Variable v : sceneVarBySid) {
            variableMap.put(v.getVarNo(), v);
        }
        // alarm id判重
        if (analogIds.contains(analog.getAlarmNo())) {
            throw new BusinessException(ResponseResult.ANALOG_ALARM_ID_REPEAT);
        }
        // 检查变量限制值格式
        if (!CommonUtils.isFloat(analog.getLimitValue())) {
            throw new BusinessException(ResponseResult.VARIABLE_LIMIT_VALUE_FORMAT_ERROR);
        }
        checkAnalog(variableMap, analog);
        sceneMapper.updateSceneAnalog(analog);
        // 修改组态状态
        sceneMapper.updateSceneState(sceneByUidAndAnalogId.getId(), Constant.SceneStatus.UNPUBLIC);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delSceneAnalogData(Long uid, List<Long> analogIds) {
        // 校验是否有重复id
        Set<Long> set = new HashSet<>(analogIds);
        if (set.size() != analogIds.size()) {
            throw new BusinessException(ResponseResult.LIST_CONTAIN_DUPLICATE_ID);
        }
        // 校验第一个id的组态
        Scene sceneByAnalogId = sceneMapper.getSceneByAnalogId(analogIds.get(0));
        if (sceneByAnalogId == null || !sceneByAnalogId.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_ANALOG_ALARM);
        }
        // 校验组态状态
        checkSceneState(sceneByAnalogId);

        // 校验其他id
        List<Long> sceneAnalogIdBySceneId = sceneMapper.getSceneAnalogIdBySceneId(sceneByAnalogId.getId());
        for (Long id : analogIds) {
            if (!sceneAnalogIdBySceneId.contains(id)) {
                throw new BusinessException(ResponseResult.CONNECT_ID_BELONG_TO_DIFF_SCENE);
            }
        }
        if (!analogIds.isEmpty()) {
            sceneMapper.deleteSceneAnalog(analogIds);
        }
        // 修改组态状态
        sceneMapper.updateSceneState(sceneByAnalogId.getId(), Constant.SceneStatus.UNPUBLIC);
    }

    @Override
    public DiscreteAlarm getOneSceneDiscreteData(Long uid, Long discreteId) {
        // 检查用户是否拥有离散量
        DiscreteAlarm sceneDiscreteByUidAndDiscreteId = sceneMapper.getSceneDiscreteByUidAndDiscreteId(uid, discreteId);
        if (sceneDiscreteByUidAndDiscreteId == null) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_DISCRETE_ALARM);
        }
        return sceneDiscreteByUidAndDiscreteId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveSceneDiscreteData(Long uid, DiscreteAlarm discrete) {
        // 检查是否拥有此组态id
        Scene sceneByUidAndSid = sceneMapper.getSceneByUidAndSid(uid, discrete.getSceneId());
        if (sceneByUidAndSid == null) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        checkSceneState(sceneByUidAndSid);

        List<DiscreteAlarm> sceneDiscreteAlarmBySid = sceneMapper.getSceneDiscreteAlarmBySid(discrete.getSceneId());
        List<Variable> sceneVarBySid = sceneMapper.getSceneVarBySid(discrete.getSceneId());
        if (sceneDiscreteAlarmBySid.size() >= 10000) {
            throw new BusinessException(ResponseResult.DISCRETE_ALARM_TOO_MUCH);
        }
        List<Integer> discreteIds = new ArrayList<>();
        Map<Integer, Variable> variableMap = new HashMap<>();
        for (DiscreteAlarm d : sceneDiscreteAlarmBySid) {
            discreteIds.add(d.getAlarmNo());
        }
        for (Variable v : sceneVarBySid) {
            variableMap.put(v.getVarNo(), v);
        }
        // id判重
        if (discreteIds.contains(discrete.getAlarmNo())) {
            throw new BusinessException(ResponseResult.DISCRETE_ALARM_ID_REPEAT);
        }
        checkDiscrete(discrete, variableMap);
        discrete.setSceneId(discrete.getSceneId());
        sceneMapper.saveSceneDiscrete(discrete);
        // 修改组态状态
        sceneMapper.updateSceneState(discrete.getSceneId(), Constant.SceneStatus.UNPUBLIC);
    }

    private void checkDiscrete(DiscreteAlarm d, Map<Integer, Variable> variableMap) {
        // 检查触发变量是否有效
        Variable variable = variableMap.get(d.getTrigVarNo());
        if (variable == null || Constant.DataTypeLen.DInt.equals(variable.getDataType()) || Constant.DataTypeLen.DWord.equals(
                variable.getDataType()) || Constant.DataTypeLen.Real.equals(variable.getDataType())
                || Constant.DataTypeLen.Timer.equals(variable.getDataType())) {
            throw new BusinessException(ResponseResult.DISCRETE_ALARM_TRIGGER_VAR_INVALID);
        }
        // 检查触发位
        if (Constant.DataTypeLen.Bool.equals(variable.getDataType())) {
            if (d.getTrigBit() != 0) {
                throw new BusinessException(ResponseResult.DISCRETE_ALARM_TRIGGER_BIT_INVALID);
            }
        } else {
            if (d.getTrigBit() < 0 || d.getTrigBit() > 15) {
                throw new BusinessException(ResponseResult.DISCRETE_ALARM_TRIGGER_BIT_INVALID);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSceneDiscreteData(Long uid, DiscreteAlarm discrete) {
        // 检查用户是否拥有离散量
        Scene sceneByUidAndDiscreteId = sceneMapper.getSceneByUidAndDiscreteId(uid, discrete.getId());
        if (sceneByUidAndDiscreteId == null) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_DISCRETE_ALARM);
        }

        checkSceneState(sceneByUidAndDiscreteId);

        List<DiscreteAlarm> sceneDiscreteAlarmBySid =
                sceneMapper.getSceneDiscreteAlarmBySid(sceneByUidAndDiscreteId.getId());
        List<Variable> sceneVarBySid = sceneMapper.getSceneVarBySid(sceneByUidAndDiscreteId.getId());
        List<Integer> discreteIds = new ArrayList<>();
        Map<Integer, Variable> variableMap = new HashMap<>();
        DiscreteAlarm dis = null;
        for (DiscreteAlarm d : sceneDiscreteAlarmBySid) {
            discreteIds.add(d.getAlarmNo());
            if (d.getId().equals(discrete.getId())) {
                dis = d;
            }
        }
        // 删除正在修改的离散量，便于判重
        sceneDiscreteAlarmBySid.remove(dis);
        for (Variable v : sceneVarBySid) {
            variableMap.put(v.getVarNo(), v);
        }
        // id判重
        if (CommonUtils.isRepeatInCollection(discreteIds)) {
            throw new BusinessException(ResponseResult.DISCRETE_ALARM_ID_REPEAT);
        }
        checkDiscrete(discrete, variableMap);
        sceneMapper.updateSceneDiscrete(discrete);
        // 修改组态状态
        sceneMapper.updateSceneState(sceneByUidAndDiscreteId.getId(), Constant.SceneStatus.UNPUBLIC);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delSceneDiscreteData(Long uid, List<Long> discreteIds) {
        // 校验是否有重复id
        Set<Long> set = new HashSet<>(discreteIds);
        if (set.size() != discreteIds.size()) {
            throw new BusinessException(ResponseResult.LIST_CONTAIN_DUPLICATE_ID);
        }
        // 校验第一个id的组态
        Scene sceneByDiscreteId = sceneMapper.getSceneByDiscreteId(discreteIds.get(0));
        if (sceneByDiscreteId == null || !sceneByDiscreteId.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_DISCRETE_ALARM);
        }
        // 校验组态状态
        checkSceneState(sceneByDiscreteId);

        // 校验其他id
        List<Long> sceneDiscreteIdBySceneId = sceneMapper.getSceneDiscreteIdBySceneId(sceneByDiscreteId.getId());
        for (Long id : discreteIds) {
            if (!sceneDiscreteIdBySceneId.contains(id)) {
                throw new BusinessException(ResponseResult.CONNECT_ID_BELONG_TO_DIFF_SCENE);
            }
        }
        if (!discreteIds.isEmpty()) {
            sceneMapper.deleteSceneDiscrete(discreteIds);
        }
        // 修改组态状态
        sceneMapper.updateSceneState(sceneByDiscreteId.getId(), Constant.SceneStatus.UNPUBLIC);
    }

    @Override
    public List<DriveType> getAllDriveType() {
        List<DriveType> driveTypes = new ArrayList<>();
        driveTypes.add(new DriveType(Constant.ProtocolValue.GATEWAY, Constant.ProtocolType.GATEWAY));
        return driveTypes;
    }

    @Override
    public List<VarAttribute> getVarAddrByDriveTypeAndDataType(Integer num) {
        List<VarAttribute> varAttributes = new ArrayList<>();
        if (num.equals(Constant.ProtocolValue.GATEWAY)) {
            // Char
            VarAttribute varAttribute = new VarAttribute();
            List<VarAddr> varAddrs = new ArrayList<>();
            varAttribute.setDataType(Constant.DataTypeLen.Char);
            varAttribute.setDataLen(1);
            varAttribute.setRequestInteger(true);
            varAttribute.setIsAnalogVarValid(true);
            varAttribute.setAnalogMinVal(-128f);
            varAttribute.setAnalogMaxVal(127f);
            varAttribute.setIsDiscreteVarValid(true);
            varAttribute.setDiscreteLowerLimit(0);
            varAttribute.setDiscreteUpperLimit(15);

            VarAddr varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("V");
            List<VarAddrLine> varAddrLines = new ArrayList<>();
            VarAddrLine varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("VB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65535);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("I");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("IB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32767);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("Q");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("QB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32767);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("M");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("MB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32767);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);
            varAttribute.setVarAddrList(varAddrs);
            varAttributes.add(varAttribute);

            // Byte
            varAttribute = new VarAttribute();
            varAddrs = new ArrayList<>();
            varAttribute.setDataType(Constant.DataTypeLen.Byte);
            varAttribute.setDataLen(1);
            varAttribute.setRequestInteger(true);
            varAttribute.setIsAnalogVarValid(true);
            varAttribute.setAnalogMinVal(0f);
            varAttribute.setAnalogMaxVal(255f);
            varAttribute.setIsDiscreteVarValid(true);
            varAttribute.setDiscreteLowerLimit(0);
            varAttribute.setDiscreteUpperLimit(15);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("V");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("VB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65535);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("I");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("IB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32767);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("Q");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("QB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32767);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("M");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("MB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32767);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("DB");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(254);
            varAddrLines.add(varAddrLine);
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DBB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65535);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);
            varAttribute.setVarAddrList(varAddrs);
            varAttributes.add(varAttribute);

            // Int
            varAttribute = new VarAttribute();
            varAddrs = new ArrayList<>();
            varAttribute.setDataType(Constant.DataTypeLen.Int);
            varAttribute.setDataLen(2);
            varAttribute.setRequestInteger(true);
            varAttribute.setIsAnalogVarValid(true);
            varAttribute.setAnalogMinVal(-32768f);
            varAttribute.setAnalogMaxVal(32767f);
            varAttribute.setIsDiscreteVarValid(true);
            varAttribute.setDiscreteLowerLimit(0);
            varAttribute.setDiscreteUpperLimit(15);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("V");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("VW");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65534);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("I");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("IW");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32766);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("Q");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("QW");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32766);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("M");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("MW");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32766);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("C");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("C");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32766);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("DB");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(254);
            varAddrLines.add(varAddrLine);
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DBW");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65535);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);
            varAttribute.setVarAddrList(varAddrs);
            varAttributes.add(varAttribute);

            // Word
            varAttribute = new VarAttribute();
            varAddrs = new ArrayList<>();
            varAttribute.setDataType(Constant.DataTypeLen.Word);
            varAttribute.setDataLen(2);
            varAttribute.setRequestInteger(true);
            varAttribute.setIsAnalogVarValid(true);
            varAttribute.setAnalogMinVal(0f);
            varAttribute.setAnalogMaxVal(65535f);
            varAttribute.setIsDiscreteVarValid(true);
            varAttribute.setDiscreteLowerLimit(0);
            varAttribute.setDiscreteUpperLimit(15);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("V");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("VW");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65534);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("I");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("IW");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32766);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("Q");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("QW");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32766);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("M");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("MW");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32766);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("DB");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(254);
            varAddrLines.add(varAddrLine);
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DBW");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65534);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);
            varAttribute.setVarAddrList(varAddrs);
            varAttributes.add(varAttribute);

            // DInt
            varAttribute = new VarAttribute();
            varAddrs = new ArrayList<>();
            varAttribute.setDataType(Constant.DataTypeLen.DInt);
            varAttribute.setDataLen(4);
            varAttribute.setRequestInteger(true);
            varAttribute.setIsAnalogVarValid(true);
            varAttribute.setAnalogMinVal(-21474836480f);
            varAttribute.setAnalogMaxVal(2147483647f);
            varAttribute.setIsDiscreteVarValid(false);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("V");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("VD");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65532);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("I");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("ID");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32764);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("Q");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("QD");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32764);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("M");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("MD");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32764);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("DB");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(254);
            varAddrLines.add(varAddrLine);
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DBD");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65532);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);
            varAttribute.setVarAddrList(varAddrs);
            varAttributes.add(varAttribute);

            // DWord
            varAttribute = new VarAttribute();
            varAddrs = new ArrayList<>();
            varAttribute.setDataType(Constant.DataTypeLen.DWord);
            varAttribute.setDataLen(4);
            varAttribute.setRequestInteger(true);
            varAttribute.setIsAnalogVarValid(true);
            varAttribute.setAnalogMinVal(0f);
            varAttribute.setAnalogMaxVal(4294967295f);
            varAttribute.setIsDiscreteVarValid(false);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("V");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("VD");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65532);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("I");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("ID");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32764);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("Q");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("QD");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32764);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("M");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("MD");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32764);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("DB");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(254);
            varAddrLines.add(varAddrLine);
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DBD");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65532);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);
            varAttribute.setVarAddrList(varAddrs);
            varAttributes.add(varAttribute);

            // Real
            varAttribute = new VarAttribute();
            varAddrs = new ArrayList<>();
            varAttribute.setDataType(Constant.DataTypeLen.Real);
            varAttribute.setDataLen(4);
            varAttribute.setRequestInteger(false);
            varAttribute.setIsAnalogVarValid(true);
            varAttribute.setAnalogMinVal(-Float.MAX_VALUE);
            varAttribute.setAnalogMaxVal(Float.MAX_VALUE);
            varAttribute.setIsDiscreteVarValid(false);


            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("V");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("VD");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65532);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("I");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("ID");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32764);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("Q");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("QD");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32764);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("M");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("MD");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32764);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("DB");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(254);
            varAddrLines.add(varAddrLine);
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DBD");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65532);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);
            varAttribute.setVarAddrList(varAddrs);
            varAttributes.add(varAttribute);

            // Bool
            varAttribute = new VarAttribute();
            varAddrs = new ArrayList<>();
            varAttribute.setDataType(Constant.DataTypeLen.Bool);
            varAttribute.setDataLen(0);
            varAttribute.setIsAnalogVarValid(false);
            varAttribute.setIsDiscreteVarValid(true);
            varAttribute.setDiscreteLowerLimit(0);
            varAttribute.setDiscreteUpperLimit(0);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("V");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("V");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65536);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("I");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("I");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32768);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("Q");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("Q");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32768);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("M");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("M");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32768);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("DB");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(254);
            varAddrLines.add(varAddrLine);
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DBX");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65536);
            varAddrLines.add(varAddrLine);
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("Bit");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(7);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);
            varAttribute.setVarAddrList(varAddrs);
            varAttributes.add(varAttribute);

            // StringChar
            varAttribute = new VarAttribute();
            varAddrs = new ArrayList<>();
            varAttribute.setDataType(Constant.DataTypeLen.StringChar);
            varAttribute.setDataLen(10);
            varAttribute.setIsAnalogVarValid(false);
            varAttribute.setIsDiscreteVarValid(true);
            varAttribute.setDiscreteLowerLimit(0);
            varAttribute.setDiscreteUpperLimit(15);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("V");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("VB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65536);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("I");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("IB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32768);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("Q");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("QB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32768);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("M");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("MB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32768);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("DB");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(254);
            varAddrLines.add(varAddrLine);
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("DBB");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(65536);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);
            varAttribute.setVarAddrList(varAddrs);
            varAttributes.add(varAttribute);

            // Timer
            varAttribute = new VarAttribute();
            varAddrs = new ArrayList<>();
            varAttribute.setDataType(Constant.DataTypeLen.Timer);
            varAttribute.setDataLen(4);
            varAttribute.setRequestInteger(true);
            varAttribute.setIsAnalogVarValid(true);
            varAttribute.setAnalogMinVal(0f);
            varAttribute.setAnalogMaxVal(9990000f);
            varAttribute.setIsDiscreteVarValid(false);

            varAddr = new VarAddr();
            varAddr.setScopeName("范围");
            varAddr.setScopeValue("T");
            varAddrLines = new ArrayList<>();
            varAddrLine = new VarAddrLine();
            varAddrLine.setFieldName("TW");
            varAddrLine.setFieldMinVal(0);
            varAddrLine.setFieldMaxVal(32764);
            varAddrLines.add(varAddrLine);
            varAddr.setVarAddrLineList(varAddrLines);
            varAddrs.add(varAddr);
            varAttribute.setVarAddrList(varAddrs);
            varAttributes.add(varAttribute);

        } else {
            throw new BusinessException(ResponseResult.CONNECT_PROTOCOL_ONLY_SUPPORT_GETWAY);
        }
        return varAttributes;
    }

    @Override
    public PageResult getSceneGroups(Long uid, PageRequest pageRequest) {
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<SceneGroup> sceneGroupByUid = sceneMapper.getSceneGroupByUid(uid);
        List<SceneGroup> topFolder = new ArrayList<>();
        Map<Long, SceneGroup> map = new HashMap<>();
        for (SceneGroup s : sceneGroupByUid) {
            map.put(s.getId(), s);
        }
        for (SceneGroup sg : sceneGroupByUid) {
            if (sg.getParentId().equals(0L)) {
                topFolder.add(sg);
            } else {
                List<SceneGroup> sceneGroups = map.get(sg.getParentId()).getSceneGroups();
                if (sceneGroups == null) {
                    sceneGroups = new ArrayList<>();
                    map.get(sg.getParentId()).setSceneGroups(sceneGroups);
                }
                sceneGroups.add(sg);
            }
        }
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(topFolder));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void runScene(Long uid, Long sceneId, Boolean command) {
        // 校验组态
        Scene sceneById = sceneMapper.getSceneById(sceneId);
        if (sceneById == null || !sceneById.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        // 运行组态
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userId", uid);
        jsonObject.put("sceneId", sceneId);
        if (command) {
            // 校验组态是否发布
            if (sceneById.getState().compareTo(Constant.SceneStatus.PUBLIC) < 0) {
                throw new BusinessException(ResponseResult.SCENE_NOT_PUBLIC);
            }
            // 检查组态连接是否有设备
            List<Long> connIds = sceneMapper.getSceneConnectIdBySceneId(sceneId);
            if (connIds.contains(-1L)) {
                throw new BusinessException(ResponseResult.SCENE_CONNECT_HAVE_NO_DEVICE);
            }
            if (sceneById.getState().compareTo(Constant.SceneStatus.RUNNING) >= 0) {
                throw new BusinessException(ResponseResult.SCENE_ALREADY_START);
            }
            jsonObject.put("code", Constant.RBTMQCMD.START_SCENE);
            // 更新组态中的地址和状态，使用组态中的设备地址
            List<Device> sceneDeviceAddresses = sceneMapper.getSceneDeviceAddresses(sceneId);
            int i = 0;
            if (sceneDeviceAddresses != null && !sceneDeviceAddresses.isEmpty()) {
                for (; i < sceneDeviceAddresses.size(); i++) {
                    Device device = sceneDeviceAddresses.get(i);
                    if (device != null) {
                        if (device.getLongitude() != null && device.getLatitude() != null) {
                            sceneMapper.updateSceneStateAndAddress(sceneId, device.getLongitude(),
                                    device.getLatitude());
                            break;
                        }
                    }
                }
            }
        } else { // 停止组态
            jsonObject.put("code", Constant.RBTMQCMD.STOP_SCENE);
        }
        rabbitTemplate.convertAndSend(Constant.Rabbitmq.WEB_TO_CLIENT_EXCHANGE, Constant.Rabbitmq.WEB_TO_CLIENT_ROUTING_KEY,
                jsonObject, message -> {
                    message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                    return message;
                });
    }


//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public void saveSceneDevice(Long uid, List<SceneDevice> sceneDevices) {
//        // 根据列表第一个连接获取组态
//        Scene sceneByConnId = sceneMapper.getSceneByConnId(sceneDevices.get(0).getConnId());
//        // 校验用户是否拥有组态
//        if (sceneByConnId == null || !sceneByConnId.getOwnerId().equals(uid)) {
//            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
//        }
//        // 校验列表元素是否重复
//        Set<SceneDevice> set = new HashSet<>(sceneDevices);
//        if (set.size() != sceneDevices.size()) {
//            throw new BusinessException(ResponseResult.LIST_CONTAIN_DUPLICATE_ID);
//        }
//
//        Set<Long> connIds = new HashSet<>();
//        Set<Long> devIds = new HashSet<>();
//        List<Long> sceneConnectIdBySid = sceneMapper.getSceneConnectIdBySid(sceneByConnId.getId());
//        List<Long> myDeviceIdByUid = deviceMapper.getMyDeviceIdByUid(uid);
//        for (SceneDevice sd : sceneDevices) {
//            // 检查连接和设备是否重复
//            if (connIds.contains(sd.getConnId())) {
//                throw new BusinessException(ResponseResult.CONNECT_ID_FIELD_REPEAT);
//            }
//            connIds.add(sd.getConnId());
//            if (sd.getDeviceId() != null) {
//                if (devIds.contains(sd.getDeviceId())) {
//                    throw new BusinessException(ResponseResult.DEVICE_ID_DUPLICATE);
//                }
//                devIds.add(sd.getDeviceId());
//            }
//            // 校验组态是否包含连接
//            if (!sceneConnectIdBySid.contains(sd.getConnId())) {
//                throw new BusinessException(ResponseResult.SCENE_DO_NOT_CONTAIN_THIS_CONNECT,
//                        ",组态id:" + sceneByConnId.getId() + ",连接id:" + sd.getConnId());
//            }
//            // 校验用户是否拥有设备
//            if (sd.getDeviceId() != null && !myDeviceIdByUid.contains(sd.getDeviceId())) {
//                throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_DEVICE, ",id:" + sd.getDeviceId());
//            }
//        }
//        // 存入数据库
//        sceneMapper.updateSceneDevice(sceneDevices);
//    }

    @Override
    public List<ConnectDevice> getSceneDevice(Long uid, Long sceneId) {
        // 校验组态
        Scene sceneById = sceneMapper.getSceneById(sceneId);
        if (sceneById == null || !sceneById.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        List<ConnectDevice> sceneDeviceBySceneId = sceneMapper.getSceneDeviceBySceneId(sceneId);
        return sceneDeviceBySceneId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateConnDevice(Long uid, ConnDevice connDevice) {
        // 获取组态
        Scene sceneByConnId = sceneMapper.getSceneByConnId(connDevice.getConnId());
        // 校验用户是否拥有包含此连接的组态
        if (sceneByConnId == null || !sceneByConnId.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_CONNECT);
        }
        // 组态状态为运行以及之后的状态不允许修改配置设备
        if (sceneByConnId.getState().compareTo(Constant.SceneStatus.RUNNING) >= 0) {
            throw new BusinessException(ResponseResult.CAN_NOT_MODIFY_DEVICE_WITH_SCENE_RUNNING);
        }
        Long sceneConnectDeviceIdByConnId = sceneMapper.getSceneConnectDeviceIdByConnId(connDevice.getConnId());
        // 组态连接中deviceId没变
        if (connDevice.getDeviceId().equals(sceneConnectDeviceIdByConnId)) {
            return;
        }
        // 设备id为-1，则为取消设备与组态连接的关联
        if (connDevice.getDeviceId() != -1) {
            // 检查设备是否是我的设备
            Integer deviceInMyDevice = sceneMapper.isDeviceInMyDevice(uid, connDevice.getDeviceId());
            if (deviceInMyDevice == 0) {
                throw new BusinessException(ResponseResult.DEVICE_NOT_IN_MY_LIST);
            }
            // 检查设备是否已经配置了组态
            Integer deviceConfigSceneConn = sceneMapper.isDeviceConfigSceneConn(sceneByConnId.getId(), connDevice);
            if (deviceConfigSceneConn != 0) {
                throw new BusinessException(ResponseResult.DEVICE_ALREADY_CONFIG_CONN_IN_SCENE);
            }
        }
        // 存入数据库
        sceneMapper.updateConnDevice(connDevice);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delSceneDevice(Long uid, List<Long> connIds) {
        // 根据列表第一个连接获取组态
        Scene sceneByConnId = sceneMapper.getSceneByConnId(connIds.get(0));
        // 校验用户是否拥有组态
        if (sceneByConnId == null || !sceneByConnId.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        // 校验列表元素是否重复
        Set<Long> set = new HashSet<>(connIds);
        if (set.size() != connIds.size()) {
            throw new BusinessException(ResponseResult.LIST_CONTAIN_DUPLICATE_ID);
        }
        List<Long> sceneConnectIdBySid = sceneMapper.getSceneConnectIdBySid(sceneByConnId.getId());
        for (Long id : connIds) {
            // 校验组态是否包含连接
            if (!sceneConnectIdBySid.contains(id)) {
                throw new BusinessException(ResponseResult.SCENE_DO_NOT_CONTAIN_THIS_CONNECT);
            }
        }
        sceneMapper.deleteSceneDevice(connIds);
    }

    @Override
    public List<Device> getSceneDevices(Long userId, Long sid) {
        Scene sceneById = sceneMapper.getSceneById(sid);
        if (sceneById == null || !sceneById.getOwnerId().equals(userId)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        return sceneMapper.getSceneDevices(sid);
    }

    @Override
    public Variable getSceneVarInfo(Long userId, Long sid, Integer varNo) {
        // 检查组态是否属于用户
        Scene sceneById = sceneMapper.getSceneById(sid);
        if (sceneById == null || sceneById.equals(userId)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        Variable sceneVarBySidAndVarNo = sceneMapper.getSceneVarBySidAndVarNo(sid, varNo);
        if (sceneVarBySidAndVarNo == null) {
            throw new BusinessException(ResponseResult.SCENE_NOT_HAVE_THIS_VARNO);
        }
        return sceneVarBySidAndVarNo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void copySceneInfo(Long ownerId, Long sceneId) {
        // 检查组态信息是否属于用户
        Scene sceneById = sceneMapper.getSceneById(sceneId);
        if (sceneById == null || !sceneById.getOwnerId().equals(ownerId)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        // 查询数据库中以该组态名开头的所有组态名，如果该组态名太长需要截断，目的为了生成一个不重复的新组态名
        String sceneNamePrefix = getSceneNamePrefix(sceneById.getName());
        List<String> sceneNames = sceneMapper.getSceneNameByPrefix(sceneNamePrefix);
        Set<String> set = new HashSet<>(sceneNames);
        String differentSceneName = getDifferentSceneName(sceneNamePrefix, set);
        // 更新组态信息
        sceneById.setName(differentSceneName);
        sceneById.setCreateDate(new Date());
        sceneById.setState(Constant.SceneStatus.UNPUBLIC);
        sceneById.setDescription("copy by " + sceneNamePrefix);
        sceneMapper.saveSceneInfo(sceneById);
        // 获取组态连接，变量，模拟量，离散量信息
        List<Connection> sceneConnectBySid = sceneMapper.getSceneConnectBySid(sceneId);
        List<Variable> sceneVarBySid = sceneMapper.getSceneVarBySid(sceneId);
        List<AnalogAlarm> sceneAnalogAlarmBySid = sceneMapper.getSceneAnalogAlarmBySid(sceneId);
        List<DiscreteAlarm> sceneDiscreteAlarmBySid = sceneMapper.getSceneDiscreteAlarmBySid(sceneId);

        // 存入数据库
        if (sceneConnectBySid != null && !sceneConnectBySid.isEmpty()) {
            sceneMapper.saveSceneConnData(sceneById.getId(), sceneConnectBySid);
        }
        if (sceneVarBySid != null && !sceneVarBySid.isEmpty()) {
            sceneMapper.saveSceneVarData(sceneById.getId(), sceneVarBySid);
        }
        if (sceneAnalogAlarmBySid != null && !sceneAnalogAlarmBySid.isEmpty()) {
            sceneMapper.saveSceneAnalogAlarmData(sceneById.getId(), sceneAnalogAlarmBySid);
        }
        if (sceneDiscreteAlarmBySid != null && !sceneDiscreteAlarmBySid.isEmpty()) {
            sceneMapper.saveSceneDiscreteAlarmData(sceneById.getId(), sceneDiscreteAlarmBySid);
        }
    }

    @Override
    public List<ConnectDevice> getSceneConfigDevice(Long userId, Long sceneId) {
        // 检查组态信息是否属于用户
        Scene sceneById = sceneMapper.getSceneById(sceneId);
        if (sceneById == null || !sceneById.getOwnerId().equals(userId)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_SCENE);
        }
        // 获取能用于配置组态连接的在线设备
        List<ConnectDevice> sceneConnectDevices = sceneMapper.getSceneConnectDevices(userId, sceneId, Constant.DevStatus.ONLINE);
        return sceneConnectDevices;
    }

    /**
     * 生成一个不重复的组态名
     *
     * @param sceneNamePrefix
     * @param set
     * @return: java.lang.String
     */
    private String getDifferentSceneName(String sceneNamePrefix, Set<String> set) {
        String ret;
        int i = 1;
        while (i <= 9999999) {
            ret = sceneNamePrefix + "_" + i;
            if (!set.contains(ret)) {
                return ret;
            }
            i++;
        }
        // 正常不会出现这个错误，除非恶意复制太多组态名
        throw new BusinessException(ResponseResult.NAME_DUPLICATE_TOO_MUCH);
    }

    /**
     * 获取组态名前缀
     *
     * @param name
     * @return: java.lang.String
     */
    private String getSceneNamePrefix(String name) {
        if (name.length() >= 24) {
            return name.substring(0, 24);
        }
        return name;
    }

    private List<Integer> getDataTypeByDriveType(Integer num) {
        List<Integer> list = new ArrayList<>();
        if (num.equals(Constant.ProtocolValue.GATEWAY)) {
            list.add(Constant.DataTypeLen.Char);
            list.add(Constant.DataTypeLen.Byte);
            list.add(Constant.DataTypeLen.Int);
            list.add(Constant.DataTypeLen.Word);
            list.add(Constant.DataTypeLen.DInt);
            list.add(Constant.DataTypeLen.DWord);
            list.add(Constant.DataTypeLen.Real);
            list.add(Constant.DataTypeLen.Bool);
            list.add(Constant.DataTypeLen.StringChar);
            list.add(Constant.DataTypeLen.Timer);
        } else {
            throw new BusinessException(ResponseResult.CONNECT_PROTOCOL_ONLY_SUPPORT_GETWAY);
        }
        return list;
    }

    // 递归获取所有子文件夹信息
    private List<SceneGroup> getAllChildSceneGroup(SceneGroup sceneGroup) {
        List<SceneGroup> sceneGroups = new ArrayList<>();
        sceneGroups.add(sceneGroup);
        List<SceneGroup> childSceneGroups = sceneGroup.getSceneGroups();
        if (childSceneGroups == null || childSceneGroups.size() == 0) {
            return sceneGroups;
        }
        for (SceneGroup sg : childSceneGroups) {
            sceneGroups.addAll(getAllChildSceneGroup(sg));
        }
        return sceneGroups;
    }

    // 递归获取所有子文件夹下的组态信息
    private List<Scene> getAllScenesFromSceneGroup(List<Scene> scenes, SceneGroup sceneGroup) {
        scenes.addAll(sceneGroup.getScenes());
        List<SceneGroup> sceneGroups = sceneGroup.getSceneGroups();
        for (SceneGroup s : sceneGroups) {
            scenes.addAll(getAllScenesFromSceneGroup(scenes, s));
        }
        return scenes;
    }

    /**
     * 校验离散量参数
     *
     * @param discreteAlarmList
     * @return: void
     */
    private void checkDiscreteAlarm(List<DiscreteAlarm> discreteAlarmList, Map<Integer, Variable> variableMap) {
        if (discreteAlarmList == null) {
            return;
        }
        if (discreteAlarmList.size() > 10000) {
            throw new BusinessException(ResponseResult.DISCRETE_ALARM_TOO_MUCH);
        }
        List<Integer> discreteIds = new ArrayList<>();
        List<String> varNames = new ArrayList<>();
        for (DiscreteAlarm d : discreteAlarmList) {
            discreteIds.add(d.getAlarmNo());
        }
        // id判重
        if (CommonUtils.isRepeatInCollection(discreteIds)) {
            throw new BusinessException(ResponseResult.DISCRETE_ALARM_ID_REPEAT);
        }
        for (DiscreteAlarm d : discreteAlarmList) {
            // 检查触发变量是否有效
            Variable variable = variableMap.get(d.getTrigVarNo());
            if (variable == null || Constant.DataTypeLen.DInt.equals(variable.getDataType()) || Constant.DataTypeLen.DWord.equals(
                    variable.getDataType()) || Constant.DataTypeLen.Real.equals(variable.getDataType())
                    || Constant.DataTypeLen.StringChar.equals(variable.getDataType())
                    || Constant.DataTypeLen.Timer.equals(variable.getDataType())) {
                throw new BusinessException(ResponseResult.DISCRETE_ALARM_TRIGGER_VAR_INVALID);
            }
            // 检查触发位
            if (Constant.DataTypeLen.Bool.equals(variable.getDataType())) {
                if (d.getTrigBit() != 0) {
                    throw new BusinessException(ResponseResult.DISCRETE_ALARM_TRIGGER_BIT_INVALID);
                }
            } else {
                if (d.getTrigBit() < 0 || d.getTrigBit() > 15) {
                    throw new BusinessException(ResponseResult.DISCRETE_ALARM_TRIGGER_BIT_INVALID);
                }
            }
        }
    }

    /**
     * 校验模拟量参数
     *
     * @param analogAlarmList
     * @return: void
     */
    private void checkAnalogAlarm(List<AnalogAlarm> analogAlarmList, Map<Integer, Variable> variableMap) {
        if (analogAlarmList == null) {
            return;
        }
        if (analogAlarmList.size() > 10000) {
            throw new BusinessException(ResponseResult.ANALOG_ALARM_TOO_MUCH);
        }
        List<Integer> analogIds = new ArrayList<>();
        List<String> varNames = new ArrayList<>();
        for (AnalogAlarm a : analogAlarmList) {
            analogIds.add(a.getAlarmNo());
        }
        // alarm id判重
        if (CommonUtils.isRepeatInCollection(analogIds)) {
            throw new BusinessException(ResponseResult.ANALOG_ALARM_ID_REPEAT);
        }
        for (AnalogAlarm a : analogAlarmList) {
            checkAnalog(variableMap, a);
        }
    }

    private void checkAnalog(Map<Integer, Variable> variableMap, AnalogAlarm a) {
        // 检查触发变量是否有效
        Variable variable = variableMap.get(a.getTrigVarNo());
        if (variable == null || Constant.DataTypeLen.Bool.equals(variable.getDataType())
                || Constant.DataTypeLen.StringChar.equals(variable.getDataType())) {
            throw new BusinessException(ResponseResult.ANALOG_ALARM_TRIGGER_VAR_INVALID);
        }
        if (a.getLimitFlag() == 1) { // 常量触发
            Integer dataType = variable.getDataType();
            float limitValue = Float.parseFloat(a.getLimitValue());
            long minVal = 0, maxVal = 0;
            if (Constant.DataTypeLen.Char.equals(dataType)) {
                minVal = -128;
                maxVal = 127;
            } else if (Constant.DataTypeLen.Byte.equals(dataType)) {
                maxVal = 255;
            } else if (Constant.DataTypeLen.Int.equals(dataType)) {
                minVal = -32768;
                maxVal = 32767;
            } else if (Constant.DataTypeLen.Word.equals(dataType)) {
                maxVal = 65535;
            } else if (Constant.DataTypeLen.DInt.equals(dataType)) {
                minVal = -2147483648;
                maxVal = 2147483647;
            } else if (Constant.DataTypeLen.DWord.equals(dataType)) {
                maxVal = 4294967295L;
            } else if (Constant.DataTypeLen.Timer.equals(dataType)) {
                maxVal = 9990000;
            }
            if ((int) limitValue > maxVal && (int) limitValue < minVal) {
                throw new BusinessException(ResponseResult.ANALOG_ALARM_LIMIT_VAR_VALUE_EXCEED_LIMIT);
            }
        } else if (a.getLimitFlag() == 2) { // 变量触发
            Variable variable1 = variableMap.get(a.getLimitVarNo());
            if (variable1 == null) {
                throw new BusinessException(ResponseResult.ANALOG_ALARM_LIMIT_VAR_INVAILID);
            }
        } else {
            throw new BusinessException(ResponseResult.ANALOG_ALARM_LIMIT_MODE_ERROR);
        }
        if (a.getTrigMode() != 0 && a.getTrigMode() != 1) {
            throw new BusinessException(ResponseResult.ANALOG_ALARM_NOT_UP_OR_DOWN_EDGE);
        }
    }

    /**
     * 校验变量参数
     *
     * @param varList
     * @param connList
     * @return: void
     */
    private void checkVar
    (List<Variable> varList, List<Connection> connList, Map<Integer, Variable> variableMap) {
        if (varList == null) {
            throw new BusinessException(ResponseResult.VARIABLE_COUNT_CAN_NOT_BE_ZERO);
        }
        // 限制变量数量在10000以内
        if (varList.size() > 10000) {
            throw new BusinessException(ResponseResult.VARIABLE_COUNT_TOO_MUCH);
        }
        List<Integer> varIds = new ArrayList<>();
        List<String> varNames = new ArrayList<>();
        List<Integer> connNos = new ArrayList<>();
        Map<Integer, Integer> connNoProtocol = new HashMap<>();
        for (Variable v : varList) {
            varIds.add(v.getVarNo());
            varNames.add(v.getName());
            variableMap.put(v.getVarNo(), v);
        }
        for (Connection c : connList) {
            connNos.add(c.getConnectNo());
            connNoProtocol.put(c.getConnectNo(), c.getDriveType());
        }
        // id,name判重
        if (CommonUtils.isRepeatInCollection(varIds)) {
            throw new BusinessException(ResponseResult.VARIABLE_ID_FIELD_REPEAT);
        }
        if (CommonUtils.isRepeatInCollection(varNames)) {
            throw new BusinessException(ResponseResult.VARIABLE_NAME_FIELD_REPEAT);
        }
        for (Variable v : varList) {
            // 检查变量对应的连接名是否存在
            if (!connNos.contains(v.getConnectNo())) {
                throw new BusinessException(ResponseResult.CONNECT_NAME_INVALID);
            }
            // 校验数据类型,长度，地址,按不同协议处理
            // 合信网关协议
            if (connNoProtocol.get(v.getConnectNo()).equals(Constant.ProtocolValue.GATEWAY)) {
                // 通过连接名获取协议，通过协议获取数据类型
                checkUDPPPI(v, connNoProtocol);
            } else {
                throw new BusinessException(ResponseResult.CONNECT_PROTOCOL_ONLY_SUPPORT_GETWAY);
            }
        }
    }

    /**
     * 获取变量位偏移量
     *
     * @param split
     * @param name
     * @return: int
     */
    private int getVarBitOffset(String[] split, String name) {
        if (split.length == 4 && "DBX".equals(split[2])) {
            String[] split1 = split[3].split("\\.");
            if (split1.length != 2 || Integer.parseInt(split1[1]) > 15) {
                throw new BusinessException(ResponseResult.VARIABLE_ADDR_INVALID);
            }
            return Integer.parseInt(split1[1]);
        }
        return -1;
    }

    /**
     * 获取变量偏移量
     *
     * @param varAddr
     * @return: int
     */
    private int getVarAddOffset(String[] varAddr) {
        // I, V，Q,M,C为整数数值部分，DB 2 DBX 3.5 这种类型为3
        // DB 2 DBX 3.5这种类型
        if (varAddr.length == 4 && "DB".equals(varAddr[2].substring(0, 2))) {
            return Integer.parseInt(varAddr[3]);
        } else if (varAddr.length == 2) {
            String substring = varAddr[1].substring(0, 1);
            if ("I".equals(substring) || "V".equals(substring) || "Q".equals(substring) || "M".equals(substring)
                    || "C".equals(substring)) {
                return (int) Double.parseDouble(varAddr[1]);
            }
        }
        // 正常不会执行到这里
        throw new BusinessException(ResponseResult.VARIABLE_ADDR_INVALID);
    }

    /**
     * 获取变量地址子区域对应的值
     *
     * @param varAddr
     * @param value
     * @return: int
     */
    private int getVarSubArea(String varAddr, String value) {
        // 如果不是DB类型，都是1，DB类型为DB后面数值
        if ("DB".equals(varAddr)) {
            return Integer.parseInt(value);
        } else {
            return 1;
        }
    }

    /**
     * 获取变量地址区域对应的值
     *
     * @param area
     * @return: int
     */
    private int getVarAreaVal(String area) {
        // 传入值带后缀，需要处理，地址区域只取首字母,V,I,Q,M...
        String substring = area.substring(0, 1);
        if ("V".equals(substring)) {
            return 132;
        } else if ("I".equals(substring)) {
            return 129;
        } else if ("Q".equals(substring)) {
            return 130;
        } else if ("M".equals(substring)) {
            return 131;
        } else if ("C".equals(substring)) {
            return 30;
        } else if ("D".equals(substring)) {
            return 133;
        } else if ("T".equals(substring)) {
            return 31;
        } else {
            throw new BusinessException(ResponseResult.VARIABLE_ADDR_INVALID);
        }
    }

    /**
     * 校验连接参数
     *
     * @param connList
     * @return: void
     */
    private void checkConnection(List<Connection> connList) {
        if (connList == null) {
            throw new BusinessException(ResponseResult.CONNECT_COUNT_CAN_NOT_BE_ZERO);
        }
        List<Integer> connIds = new ArrayList<>();
        List<String> names = new ArrayList<>();
        for (Connection c : connList) {
            connIds.add(c.getConnectNo());
            names.add(c.getName());
        }
        // id,name判重
        if (CommonUtils.isRepeatInCollection(connIds)) {
            throw new BusinessException(ResponseResult.CONNECT_ID_FIELD_REPEAT);
        }
        if (CommonUtils.isRepeatInCollection(names)) {
            throw new BusinessException(ResponseResult.CONNECT_NAME_FIELD_REPEAT);
        }
        // 目前仅支持CO-TRUST UDP PPI协议
        int connSize = connList.size();
        // 逐行检查连接参数
        for (int i = 0; i < connSize; i++) {
            // 协议类型为CO-TRUST UDP PPI协议
            if (connList.get(i).getDriveType().equals(Constant.ProtocolValue.GATEWAY)) {
                if (!"以太网".equals(connList.get(i).getPort())) {
                    throw new BusinessException(ResponseResult.CONNECT_PORT_ILLEGAL);
                }
            } else {
                throw new BusinessException(ResponseResult.CONNECT_PROTOCOL_TYPE_ERROR);
            }
        }
    }
}